package navigation

import (
	"context"
	stderrors "errors"
	"time"

	"BookStack/pkg/errors"
)

// 一些业务错误
var (
	ErrNavigationNotFound        = stderrors.New("导航不存在")
	ErrNavigationNameExists      = stderrors.New("导航名称已存在")
	ErrNavigationURLExists       = stderrors.New("导航URL已存在")
	ErrNavigationPositionInvalid = stderrors.New("导航位置无效")
	ErrNavigationParentNotFound  = stderrors.New("父导航不存在")
)

// Service 导航领域服务接口
type Service interface {
	// GetByID 通过ID获取导航
	GetByID(ctx context.Context, id uint) (*Navigation, error)

	// GetByPosition 通过位置获取导航
	GetByPosition(ctx context.Context, position string) ([]*Navigation, error)

	// List 获取导航列表
	List(ctx context.Context, page, pageSize int, position string, status *int) ([]*Navigation, int64, error)

	// Create 创建导航
	Create(ctx context.Context, params *CreateNavigationParams) (*Navigation, error)

	// Update 更新导航
	Update(ctx context.Context, params *UpdateNavigationParams) (*Navigation, error)

	// Delete 删除导航
	Delete(ctx context.Context, id uint) error

	// GetTree 获取导航树
	GetTree(ctx context.Context, position string) ([]*NavigationNode, error)

	// BatchUpdateOrder 批量更新导航排序
	BatchUpdateOrder(ctx context.Context, items []OrderItem) error

	// UpdateStatus 更新导航状态
	UpdateStatus(ctx context.Context, id uint, status int) error
}

// 导航领域服务实现
type service struct {
	repo Repository
}

// NewService 创建导航领域服务
func NewService(repo Repository) Service {
	return &service{
		repo: repo,
	}
}

// GetByID 通过ID获取导航
func (s *service) GetByID(ctx context.Context, id uint) (*Navigation, error) {
	navigation, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if navigation == nil {
		return nil, errors.New(errors.ErrCodeNavigationNotFound, "").WithDetails(map[string]interface{}{
			"navigation_id": id,
		})
	}
	return navigation, nil
}

// GetByPosition 通过位置获取导航
func (s *service) GetByPosition(ctx context.Context, position string) ([]*Navigation, error) {
	// 验证导航位置
	if !isValidPosition(position) {
		return nil, errors.New(errors.ErrCodeNavigationPositionInvalid, "").WithDetails(map[string]interface{}{
			"position": position,
		})
	}

	navigations, err := s.repo.GetByPosition(ctx, position)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return navigations, nil
}

// List 获取导航列表
func (s *service) List(ctx context.Context, page, pageSize int, position string, status *int) ([]*Navigation, int64, error) {
	// 由于仓储接口的 List 方法不支持 position 参数，我们需要先获取所有导航，然后在服务层过滤
	navigations, _, err := s.repo.List(ctx, page, pageSize)
	if err != nil {
		return nil, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	// 过滤结果
	var filteredNavigations []*Navigation
	for _, nav := range navigations {
		// 如果指定了位置，则过滤位置
		if position != "" && nav.Position != position {
			continue
		}
		// 如果指定了状态，则过滤状态
		if status != nil && nav.Status != *status {
			continue
		}
		filteredNavigations = append(filteredNavigations, nav)
	}

	return filteredNavigations, int64(len(filteredNavigations)), nil
}

// Create 创建导航
func (s *service) Create(ctx context.Context, params *CreateNavigationParams) (*Navigation, error) {
	// 检查参数
	if params.Name == "" {
		return nil, errors.New(errors.ErrCodeNavigationNameRequired, "导航名称不能为空")
	}
	if params.URL == "" {
		return nil, errors.New(errors.ErrCodeNavigationURLRequired, "导航URL不能为空")
	}
	if params.Position == "" {
		return nil, errors.New(errors.ErrCodeNavigationPositionRequired, "导航位置不能为空")
	}
	if !isValidPosition(params.Position) {
		return nil, errors.New(errors.ErrCodeNavigationPositionInvalid, "").WithDetails(map[string]interface{}{
			"position": params.Position,
		})
	}

	// 检查名称是否已存在
	exists, err := s.repo.ExistsByName(ctx, params.Name, params.Position, 0)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeNavigationNameExists, "").WithDetails(map[string]interface{}{
			"name":     params.Name,
			"position": params.Position,
		})
	}

	// 检查URL是否已存在
	exists, err = s.repo.ExistsByURL(ctx, params.URL, params.Position, 0)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeNavigationURLExists, "").WithDetails(map[string]interface{}{
			"url":      params.URL,
			"position": params.Position,
		})
	}

	// 检查父导航是否存在
	if params.ParentID > 0 {
		exists, err := s.repo.CheckParentExists(ctx, params.ParentID)
		if err != nil {
			return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
		}
		if !exists {
			return nil, errors.New(errors.ErrCodeNavigationParentNotFound, "").WithDetails(map[string]interface{}{
				"parent_id": params.ParentID,
			})
		}
	}

	// 创建导航
	now := time.Now()
	parentID := params.ParentID
	navigation := &Navigation{
		Name:        params.Name,
		URL:         params.URL,
		Icon:        params.Icon,
		Position:    params.Position,
		ParentID:    &parentID,
		Order:       params.Order,
		Status:      params.Status,
		Target:      params.Target,
		Description: params.Description,
		CreatedAt:   now,
		UpdatedAt:   now,
	}

	if err := s.repo.Create(ctx, navigation); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return navigation, nil
}

// Update 更新导航
func (s *service) Update(ctx context.Context, params *UpdateNavigationParams) (*Navigation, error) {
	// 检查参数
	if params.ID == 0 {
		return nil, errors.New(errors.ErrCodeNavigationIDRequired, "导航ID不能为空")
	}
	if params.Name == "" {
		return nil, errors.New(errors.ErrCodeNavigationNameRequired, "导航名称不能为空")
	}
	if params.URL == "" {
		return nil, errors.New(errors.ErrCodeNavigationURLRequired, "导航URL不能为空")
	}
	if params.Position == "" {
		return nil, errors.New(errors.ErrCodeNavigationPositionRequired, "导航位置不能为空")
	}
	if !isValidPosition(params.Position) {
		return nil, errors.New(errors.ErrCodeNavigationPositionInvalid, "").WithDetails(map[string]interface{}{
			"position": params.Position,
		})
	}

	// 检查导航是否存在
	navigation, err := s.repo.GetByID(ctx, params.ID)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if navigation == nil {
		return nil, errors.New(errors.ErrCodeNavigationNotFound, "").WithDetails(map[string]interface{}{
			"navigation_id": params.ID,
		})
	}

	// 检查名称是否已存在
	exists, err := s.repo.ExistsByName(ctx, params.Name, params.Position, params.ID)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeNavigationNameExists, "").WithDetails(map[string]interface{}{
			"name":     params.Name,
			"position": params.Position,
		})
	}

	// 检查URL是否已存在
	exists, err = s.repo.ExistsByURL(ctx, params.URL, params.Position, params.ID)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeNavigationURLExists, "").WithDetails(map[string]interface{}{
			"url":      params.URL,
			"position": params.Position,
		})
	}

	// 检查父导航是否存在
	if params.ParentID > 0 {
		// 不能将自己设为自己的父级
		if params.ParentID == params.ID {
			return nil, errors.New(errors.ErrCodeValidation, "不能将导航自身设为父级")
		}

		exists, err := s.repo.CheckParentExists(ctx, params.ParentID)
		if err != nil {
			return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
		}
		if !exists {
			return nil, errors.New(errors.ErrCodeNavigationParentNotFound, "").WithDetails(map[string]interface{}{
				"parent_id": params.ParentID,
			})
		}
	}

	// 更新导航
	navigation.Name = params.Name
	navigation.URL = params.URL
	navigation.Icon = params.Icon
	navigation.Position = params.Position
	parentID := params.ParentID
	navigation.ParentID = &parentID
	navigation.Order = params.Order
	navigation.Status = params.Status
	navigation.Target = params.Target
	navigation.Description = params.Description
	navigation.UpdatedAt = time.Now()

	if err := s.repo.Update(ctx, navigation); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return navigation, nil
}

// Delete 删除导航
func (s *service) Delete(ctx context.Context, id uint) error {
	// 检查导航是否存在
	navigation, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if navigation == nil {
		return errors.New(errors.ErrCodeNavigationNotFound, "").WithDetails(map[string]interface{}{
			"navigation_id": id,
		})
	}

	// 检查是否有子导航
	children, err := s.repo.GetChildren(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if len(children) > 0 {
		return errors.New(errors.ErrCodeValidation, "该导航下有子导航，无法删除").WithDetails(map[string]interface{}{
			"navigation_id":  id,
			"children_count": len(children),
		})
	}

	// 删除导航
	if err := s.repo.Delete(ctx, id); err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return nil
}

// GetTree 获取导航树
func (s *service) GetTree(ctx context.Context, position string) ([]*NavigationNode, error) {
	// 验证导航位置
	if !isValidPosition(position) {
		return nil, errors.New(errors.ErrCodeNavigationPositionInvalid, "").WithDetails(map[string]interface{}{
			"position": position,
		})
	}

	nodes, err := s.repo.GetTree(ctx, position)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return nodes, nil
}

// BatchUpdateOrder 批量更新导航排序
func (s *service) BatchUpdateOrder(ctx context.Context, items []OrderItem) error {
	if len(items) == 0 {
		return errors.New(errors.ErrCodeValidation, "排序项不能为空")
	}

	if err := s.repo.BatchUpdateOrder(ctx, items); err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return nil
}

// UpdateStatus 更新导航状态
func (s *service) UpdateStatus(ctx context.Context, id uint, status int) error {
	// 检查状态值
	if status != StatusEnabled && status != StatusDisabled {
		return errors.New(errors.ErrCodeNavigationStatusInvalid, "导航状态无效，只能是0或1").WithDetails(map[string]interface{}{
			"status": status,
		})
	}

	// 检查导航是否存在
	navigation, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if navigation == nil {
		return errors.New(errors.ErrCodeNavigationNotFound, "").WithDetails(map[string]interface{}{
			"navigation_id": id,
		})
	}

	if err := s.repo.UpdateStatus(ctx, id, status); err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return nil
}

// 检查导航位置是否有效
func isValidPosition(position string) bool {
	validPositions := []string{
		PositionHeader,
		PositionFooter,
		PositionSidebar,
		PositionMobile,
		"main",      // 主导航
		"secondary", // 次要导航
		"quick",     // 快捷导航
		"user",      // 用户导航
		"admin",     // 管理导航
	}

	for _, p := range validPositions {
		if p == position {
			return true
		}
	}

	return false
}
